package com.changge.module.monitor.service;

import cn.hutool.json.JSONUtil;
import com.changge.common.models.vo.system.monitor.CacheInfoVO;
import com.changge.common.models.vo.system.monitor.CacheKeyVO;
import com.changge.common.models.vo.system.monitor.CacheTypeVO;
import com.changge.common.redis.enums.RedisPrefix;
import com.changge.common.redis.enums.RedisType;
import com.changge.common.redis.exception.CacheErrorCode;
import com.changge.common.redis.service.IRedisService;
import com.changge.monitor.facade.service.cache.ICacheService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 缓存管理业务逻辑接口实现类
 *
 * @author zhangrongkang
 * @since 2023/7/13
 */
@Service
public class CacheServiceImpl implements ICacheService {

    @Autowired
    private IRedisService redisService;

    /**
     * 获取所有缓存键类型
     *
     * @return 缓存键类型集合
     */
    @Override
    public List<CacheTypeVO> listRedisKeyType() {
        // 定义返回结果
        List<CacheTypeVO> result = new ArrayList<>();
        // 遍历所有Redis前缀
        for (RedisPrefix redisPrefix : RedisPrefix.values()) {
            // 缓存分类名称
            CacheTypeVO redisKeyTypeVO = CacheTypeVO.builder()
                    // 缓存名称
                    .name(redisPrefix.getKey())
                    // 备注
                    .remark(redisPrefix.getRemark()).build();
            // 添加当前Redis缓存键
            result.add(redisKeyTypeVO);
        }
        return result;
    }

    /**
     * 获取缓存键列表
     *
     * @param type 缓存类型
     * @return 缓存键列表
     */
    @Override
    public List<CacheKeyVO> listCacheKeys(String type) {
        List<CacheKeyVO> result = new ArrayList<>();
        // 获取当前缓存类型对应的所有Key
        Set<String> keys = redisService.scanKeys(type);
        for (String key : keys) {
            // 添加当前对象
            result.add(CacheKeyVO.builder()
                    // 进行展示的缓存键
                    .showKey(key.substring(key.indexOf(":") + 1))
                    // 缓存键
                    .key(key).build());
        }
        return result;
    }

    /**
     * 根据缓存键获取缓存信息
     *
     * @param key 缓存键
     * @return 缓存信息
     */
    @Override
    public CacheInfoVO getCacheInfoByKey(String key) {
        // 先构建缓存的名称以及Key
        CacheInfoVO cacheInfoVO = CacheInfoVO.builder()
                // 缓存名称
                .cacheName(key.substring(0, key.indexOf(":")))
                // 缓存键
                .cacheKey(key.substring(key.indexOf(":") + 1)).build();
        // 先获取当前缓存的类型，根据类型决定获取方式
        RedisType redisType = RedisType.getRedisType(redisService.type(key));
        if (Objects.isNull(redisType)) {
            throw CacheErrorCode.CACHE_TYPE_NOT_EXIST.exception();
        }
        // 获取缓存值
        Object cacheValue = switch (redisType) {
            // 字符类型
            case STRING_TYPE -> redisService.get(key);
            // 集合类型
            case List_TYPE -> redisService.getList(key);
        };
        // 设置缓存值
        cacheInfoVO.setCacheValue(JSONUtil.toJsonStr(cacheValue));
        return cacheInfoVO;
    }

    /**
     * 清理缓存列表
     *
     * @param type 缓存键列表
     */
    @Override
    public void clearCacheKeys(String type) {
        redisService.clearKeys(type);
    }

    /**
     * 获取缓存监控内容
     *
     * @return 缓存监控内容
     */
    @Override
    public Map<String, Object> getMonitorInfo() {
        // Redis服务信息
        Properties info = redisService.getProperties(null);
        // Redis命令统计信息
        Properties commandStats = redisService.getProperties("commandstats");
        // Redis数据库大小
        Object dbSize = redisService.getDataBaseSize();

        Map<String, Object> result = new HashMap<>(3);
        result.put("info", info);
        result.put("dbSize", dbSize);

        List<Map<String, String>> pieList = new ArrayList<>();
        commandStats.stringPropertyNames().forEach(key -> {
            Map<String, String> data = new HashMap<>(2);
            String property = commandStats.getProperty(key);
            data.put("name", StringUtils.removeStart(key, "cmdstat_"));
            data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
            pieList.add(data);
        });
        result.put("commandStats", pieList);
        return result;
    }

}
